#ifndef MY_ACTION_H
#define MY_ACTION_H

#include <map>
#include <vector>

#include "action.h"
#include "cursor.h"
#include "trace.h"
#include "models.h"

#include "modelinghelper.h"
#include "mystates.h"

using namespace std;

class DrawSegmentAction : public Action{
    private:
        Scene *scene;

    public:
        DrawSegmentAction(){}
        ~DrawSegmentAction(){}
        
        void setScene(Scene* _scene){
            this->scene = _scene;
        }
        
        void act(Trace& trace){
            this->scene->addSegment( Segment( trace[0].getScenePoint(), 
                                              trace[1].getScenePoint() ) );
        }
};

class CreateFaceAction : public Action{
    private:
        Scene *scene;
        vector<Point> polygon;
        Modeling* modeling;
        int objectId;
        int faceId;

    public:
        CreateFaceAction(){}
        ~CreateFaceAction(){}
        
        void setScene(Scene* _scene){
            this->scene = _scene;
        }
        
        void setPolygon(vector<Point> _polygon){
            this->polygon = _polygon;
        }

        void setModeling(Modeling* _modeling){
            this->modeling = _modeling;
        }        
        
        void setObjectId(int objId){
            this->objectId = objId;
        }
        
        void act(){
            Face f = modeling->factory.createFace(polygon, this->objectId);
            this->faceId = f.getId();
            modeling->addFace(f, this->objectId);
            modeling->updateScene();
        }
        
        int getFaceId(){
            return this->faceId;
        }
};


class PolygonAction : public Action{
    private:
        vector<Cursor> vertices;
        vector<Trace> edges;
        vector<Point> polygon;
        
        Scene *scene;
        
    public:
        PolygonAction(){}
        ~PolygonAction(){}
        
        void setScene(Scene* _scene){
            this->scene = _scene;
        }
        
        void setVertices(vector<Cursor> _vertices){
            this->vertices = _vertices;
        }

        void setEdges(vector<Trace> _edges){
            this->edges = _edges;
        }

        void act(Sketch& sketch){
            map<int, Trace>& traces = sketch.getTraces();
                        
            traces.clear();
            for (int k = 0; k < edges.size(); k++){
                traces[edges[k].getId()] = edges[k];
            }
            
            Point v1, v2;
            for (int z = 0; z < vertices.size()-1; z++){
                v1 = vertices[z].getScenePoint();
                v2 = vertices[(z+1)%vertices.size()].getScenePoint();
                scene->removeSegment( Segment( v1, v2) );
                
                this->polygon.push_back(vertices[z].getScenePoint()+Point(0.0,0.05,0.0));
                this->scene->addLine(v1, v2);
            }
        }
        
        vector<Point> getPolygon(){
            return this->polygon;
        }
};

class SelectionAction : public Action{
    private:
        Scene *scene;
        Modeling* modeling;
        
        int faceId;
        int state;

        int selectCategory(int id){
            if (id > 0 and id < 1000){
                return VERTEX_TYPE;
            }
            else if (id < 2000){
                return EDGE_TYPE;
            }
            else if (id < 3000){
                return FACE_TYPE;
            }
            else if (id < 90000){
                return OBJECT_TYPE;
            }
            else{
                return ENVIROMENT_TYPE;
            }
        }


        void processPick(vector<Selected> selected){
            int elemId = 99998;
            int category = ENVIROMENT_TYPE;
            unsigned long distance = 4294967294;            
            printf("Pick:\n");
            for (int i = 0; i < selected.size(); i++){
//                selected[i].show();
                if (selectCategory(selected[i].id) < category){
                    elemId = selected[i].id;
                    category = selectCategory(selected[i].id);
                }
                else if (selectCategory(selected[i].id) == category
                         and selected[i].zmin < distance){
                    distance = selected[i].zmin;
                    elemId = selected[i].id;
                    category = selectCategory(selected[i].id);
                }
            }
            choiceElement( int(elemId / 10000) * 10000, elemId);
        }


        void choiceElement(unsigned int objectId, unsigned int elemId){
            map<int, Object> &objects = modeling->getObjects();
            Object obj = objects[objectId];
            
            if ( obj.hasVertex(elemId) ){
                modeling->selectVertex(obj.getId(), elemId);
            }
            else  if ( obj.hasEdge(elemId) ){
                modeling->selectEdge(obj.getId(), elemId);
            }
            else  if ( obj.hasFace(elemId) ){
                Face &f = modeling->selectFace(obj.getId(), elemId);
                faceId = f.getId();
                Point p = ModelingHelper::selectCentroidFace(f);
                ModelingHelper::drawOrthogonalPlane(f, scene, *modeling);
                this->state = FACE_SELECTED;
            }    
            else{
                printf("\n\nNo elements selected\n\n");
            }
        }

    public:
        SelectionAction(){}
        ~SelectionAction(){}

        void setState(int _state){
            this->state = _state;
        }

        void setScene(Scene* _scene){
            this->scene = _scene;
        }        
        
        void setModeling(Modeling* _modeling){
            this->modeling = _modeling;
        }          
        
        void act(Cursor cursor){
            vector<Selected> selected = scene->selectElements( int( cursor.getX() ), int( cursor.getY() ) );
        
            processPick(selected);
        }
        
        int getState(){
            return state;
        }
        
        void setFaceId(int _id){
            this->faceId = _id;
        }
        
        int getFaceId(){
            return this->faceId;
        }        
};

#endif /* MY_ACTION_H */
